封装
- 封装的理解 - 封装是属性和方法的抽象。让数据和代码成为类的过程。 - 对属性和方法进行定义、隔离、保护。 - 形成一个类对外可操作属性和方法的接口 - 隐藏实现细节,使得代码模块化 
- 私有属性VS公开属性、私有方法VS公开方法 - 由于属性和方法都可以看作是类内部的对象,所以下面简称二者为’对象‘。 - 公开对象可以在类内部和外部使用 - 私有对象只能在类内部使用,外部直接调用时会发生AttributeError - 如需定义一个私有属性,只需要在属性名中加双下划线前缀__。这种处理方法只是修改了原有属性的名字,如果非要访问私有属性和私有方法也可以,在原名字前加下划线和类名。如_Person__count - 私有化从形式上保护了python类内部使用的逻辑,是一种程序员间的约定。 
- 保留属性 - 也叫特殊属性,双下划线开头和结尾 - 为理解python类提供了统一的属性接口 - 属性值具有特定含义,类定义后直接使用 - | 类对象的保留属性 | 描述 | 
 | —————- | ————————————— |
 | __name__ | 类的名字 |
 | __qualname__ | 以.分隔的从模块全局命名空间开始的类名称 |
 | __bases__ | 类所继承的基类名称 |
 | __dict__ | 类成员信息的字典 |- | 实例对象的保留属性 | 描述 | 
 | —————— | —————————————— |
 | __dict__ | 对象属性信息的字典,key是属性,value是值 |
 | __class__ | 类对象对象的类信息,即type信息 |
 | __doc__ | 类描述,写在类定义下的首行字符串,不能继承 |
 | __module__ | 类所在模块的名字 |
- 保留方法 - 也叫特殊方法,以双下划线开头和结尾的方法。 - 为操作python类提供了统一的方法接口 - | 常用保留方法 | 对应操作 | 描述 | 
 | ————— | —————– | ——————————– |
 | __init__() | obj = ClassName() | 初始化实例对象 |
 | __del__() | del obj | 删除实例对象 |
 | __repr__() | repr(obj) | 定义对象可打印字符串的函数逻辑 |
 | __str__() | str(obj) | 定义对象字符串转换操作的函数逻辑 |
 | __bytes__() | bytes(obj) | 字节串转换 |
 | __format__() | obj.format() | 格式化输出 |
 | __hash__() | hash(obj) | 哈希操作 |
 | __bool__() | bool(obj) | 布尔运算 |
 | __len__() | len(obj) | 对象长度 |
 | __reversed__() | obj.reversed() | 对象逆序 |
 | __abs__() | abs(obj) | 求绝对值 |
 | __int__() | int(obj) | 整数转换 |
 | __lt__() | obj1 < obj2 | 比较操作 |
 | __le__() | obj1 <= obj2 | 比较操作 |
 | __eq__() | obj1 == obj2 | 比较操作 |
 | __ne__() | obj1 != obj2 | 比较操作 |
 | __gt__() | obj1 > obj2 | 比较操作 |
 | __ge__() | obj1 >= obj2 | 比较操作 |
 | 等等 | | |
继承 Inheritance
- 什么是继承 - 原有的、已经写好的类,被继承的类叫做基类,也叫父类。 - 新构建的、继承父类的类叫做派生类,也叫子类。 - 父类的父类叫做超类。 - 一个子类可以有多个父类,这种继承方式称为多继承 - 扩展已存在的代码模块(类),实现了以类为单位的高抽象级别代码复用。 
- 如何使用【[多]继承】特性 - 1 
 2
 3
 4
 5
 6- # 在定义类时声明继承关系 
 # 父类名可以带有路径:ModuleName.BaseClassName
 # 父类可以有多个,即多继承
 class 类名(父类名1,父类名2,...,父类名n):
 def __init__(self, 参数):
 语句块- 子类基本可以完全拥有父类的属性和方法,并且根据需要可以重写继承来的属性和方法,也可以新增属性和方法。 - 所谓“基本完全拥有”指的是:子类不能继承父类的私有属性和私有方法 - 使用父类的类方法和类属性时,要使用父类的类名调用。或者super() - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26- class people(): 
 count = 0
 def __init__(self, name):
 self.name = name
 people.count += 1
 def get_name(self):
 return self.name
 class man(people):
 def __init__(self, name, wife):
 people.__init__(self, name)
 # super(man, self).__init__(name) # 也可以
 self.wife = wife
 def marrywho(self):
 return self.wife
 p0 = people('小王')
 p1 = man('小张', '小李')
 print(p1.get_name())
 print(p1.marrywho())
 print(people.count)- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39- # 多继承的规则:深度优先,从左至右 
 # 所有属性、方法,以及super()也遵从这一原则
 # 所以,多继承中父类的顺序很关键
 class Cuboid(object):
 def __init__(self, length, width, heigth):
 self.length = length
 self.width = width
 self.heigth = heigth
 def volume(self):
 return self.heigth * self.width * self.length
 def say(self):
 print('本长方体的规格是%f*%f*%f' % (self.length, self.width, self.heigth))
 class Iron(object):
 def __init__(self, density):
 self.density = density
 def say(self):
 print('铁的密度是%f' % self.density)
 class Slab(Cuboid, Iron):
 def __init__(self, length, width, heigth, density):
 Cuboid.__init__(self, length, width, heigth)
 Iron.__init__(self, density)
 def mass(self):
 return self.volume * self.density
 if __name__ == '__main__':
 block = Slab(2, 0.5, 0.5, 7.9e3)
 print(block.mass)
 block.say()
- 判定继承关系的2个内置函数 - | 函数 | 描述 | 
 | ———————- | —————————————————— |
 | isinstance(obj, cls) | 判断对象obj是否是类cls的实例或子类实例,返回True/False |
 | issubclass(cls1, cls2) | 判断类cls1是否是类cls的子类,返回True/False |
- python最基础类:object - 所有类定义时默认继承object类 - 保留属性和保留方法本质上是object类的属性和方法。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- print(object.__name__) 
 print(object.__doc__)
 print(object.__bases__)
 print(object.__class__)
 print(object.__module__)
 '''
 object
 The most base type
 ()
 <class 'type'>
 builtins
 '''
- 类的方法覆盖和属性覆盖 - 覆盖原则:就近覆盖 - 优先使用子类重写的属性和方法 - 如果子类没有重写,则去寻找父类的属性和方法 - 如果父类中也没有,则去寻找超类的属性和方法 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39- class A(object): 
 var = 999
 def say(self):
 print('AAA')
 # 未重写/覆盖A的类属性var和实例方法say
 class B(A):
 pass
 # 重写A的类属性var和实例方法say
 class C(A):
 var = 0
 def say(self):
 super().say()
 print('I am C')
 print(B.var)
 print(C.var)
 a = A()
 a.say()
 b = B()
 b.say()
 c = C()
 c.say()
 '''
 999
 0
 AAA
 AAA
 I am C
 AAA
 '''
多态
- 多态的理解 - 同一操作作用于不同的对象,可以有不同的解释,产生不同的结果,这就是多态。 - 一种接口多种实现。 - 封装和继承实现的是代码重用,多态实现的是接口重用。 - 多态是父类使用子类的方法。 - 继承是子类使用父类的方法。 - 在C++中是通过派生类覆写基类中的虚函数型方法来实现的。简单来说就是将子类类型的指针赋值给父类类型的指针。编译时多态性通过重载实现;运行时多态性通过覆写虚成员实现。重载是对同名函数的不同参数列表实现。覆写是同名函数、同参数列表、同返回值类型的实现。 - 由于python是动态语言以及强大的参数传递功能,重载这一特性天然支持。当然,重载并不等同于多态。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28- class Animal(object): 
 def run(self):
 print('Animal is running...')
 class Dog(Animal):
 def run(self):
 print('Dog is running...')
 class Cat(Animal):
 def run(self):
 print('Cat is running...')
 def run_twice(animal):
 animal.run()
 animal.run()
 if __name__ == '__main__':
 d = Dog()
 c = Cat()
 print(isinstance(d, Animal))
 run_twice(d)
 run_twice(c)- 对扩展开放,对修改封闭。 
- 参数类型的多态 
- 参数形式的多态